package com.net.xpay.web.controller.open;

import com.alipay.api.AlipayApiException;
import com.google.common.base.Strings;
import com.net.xpay.core.model.*;
import com.net.xpay.web.dto.OpenAlipayUserDto;
import com.net.common.exception.BusinessException;
import com.net.common.model.ResultData;
import com.net.common.util.SerializationUtil;
import com.net.xpay.alipay.PoseidonAlipayClient;
import com.net.xpay.common.annotation.ApiMonitoring;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.helper.RedisHelper;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.constant.RedisKey;
import com.net.xpay.core.domain.AlipayUser;
import com.net.xpay.core.enums.AlipayUserStatus;
import com.net.xpay.core.helper.SignerCheckHelper;
import com.net.xpay.core.manager.AlipayUserManager;
import com.net.xpay.core.service.OpenPayTransService;
import com.net.shard.ShardUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 2020/6/28 09:46

 */
@RestController
@Slf4j
@RequestMapping("/open/alipay-auth")
@Api(tags = "第三方开放调用/签约接口", description = "第三方开放调用 签约接口 net")
public class OpenAlipayAuthController {

    @Autowired
    private OpenPayTransService openPayTransService;

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private SignerCheckHelper signerCheckHelper;

    @Autowired
    private AlipayUserManager alipayUserManager;

    @Autowired
    private PoseidonAlipayClient xpayAlipayClient;

    @Autowired
    private RedisHelper redisHelper;

    /**
     * 获取支付宝授权页面, 可进行签约
     */
    @ApiMonitoring(value = "批量有密/签约支付宝")
    @ApiOperation(value = "跳转支付宝签约页面")
    @PostMapping("/go-auth-page")
    @ResponseBody
    public ResultData<String> goAuthPage(@RequestBody OpenAlipayAuthModel authModel) throws AlipayApiException {
        log.info("goAuthPage|params={}", SerializationUtil.obj2String(authModel));
        if (Strings.isNullOrEmpty(authModel.getAlipayNickName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入支付宝账号");
        }
        if (Strings.isNullOrEmpty(authModel.getReturnUrl())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "签约完成回跳地址不能为空");
        }

        User user = signerCheckHelper.checkSign(authModel);
        UserShard userShard = userShardManager.getById(user.getId());
        try {
            ShardUtil.setShardContext(userShard.getShardId());
            return new ResultData<>(doAlipayAuth(authModel, user));
        } finally {
            ShardUtil.cleanShardContext();
        }
    }

    /**
     * 获取支付宝授权页面, 可进行签约
     */
    @ApiOperation(value = "跳转支付宝签约页面")
    @PostMapping("/get-sign-page")
    @ResponseBody
    public ResultData<String> getSignPage(@RequestBody OpenAlipaySignModel authModel) throws AlipayApiException {
        log.info("getSignPage|params={}", SerializationUtil.obj2String(authModel));
        if (Strings.isNullOrEmpty(authModel.getSignBizNo())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入外部签约事务号");
        }
        if (authModel.getSignBizNo().length() > 64) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "外部签约事务号长度不可超过64个字符");
        }
        if (Strings.isNullOrEmpty(authModel.getReturnUrl())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "签约完成回跳地址不能为空");
        }

        User user = signerCheckHelper.checkSign(authModel);
        UserShard userShard = userShardManager.getById(user.getId());
        try {
            ShardUtil.setShardContext(userShard.getShardId());
            return new ResultData<>(doAlipaySign(authModel, user));
        } finally {
            ShardUtil.cleanShardContext();
        }
    }


    /**
     * 商家解约
     */
    @ApiOperation(value = "商家解约")
    @PostMapping("/un-sign")
    @ResponseBody
    public ResultData<Boolean> unSignAlipayUser(@RequestBody OpenAlipayUnsignModel unsignModel) {
        log.info("unSignAlipayUser|params={}", SerializationUtil.obj2String(unsignModel));
        if (Strings.isNullOrEmpty(unsignModel.getAlipayNickName()) && Strings.isNullOrEmpty(unsignModel.getSignBizNo())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入支付宝账号");
        }

        User user = signerCheckHelper.checkSign(unsignModel);
        UserShard userShard = userShardManager.getById(user.getId());
        try {
            ShardUtil.setShardContext(userShard.getShardId());
            if (!Strings.isNullOrEmpty(unsignModel.getAlipayNickName())) {
                AlipayUser alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), unsignModel.getAlipayNickName());
                if (alipayUser == null) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "支付宝账号不存在");
                }
                alipayUser.setStatus(AlipayUserStatus.NO);
                alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
            } else if (!Strings.isNullOrEmpty(unsignModel.getSignBizNo())) {
                AlipayUser alipayUser = alipayUserManager.findBySignBizNo(user.getId(), unsignModel.getSignBizNo());
                if (alipayUser == null) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "外部事务号不存在");
                }
                alipayUser.setStatus(AlipayUserStatus.NO);
                alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
            }


            return new ResultData<>(true);
        } finally {
            ShardUtil.cleanShardContext();
        }
    }

    /**
     * 查询支付宝签约结果
     */
    @ApiMonitoring(value = "批量有密/查询支付宝签约结果")
    @ApiOperation("查询支付宝签约结果")
    @PostMapping("/get-auth-result")
    public ResultData<OpenAlipayUserDto> getAlipayAuthResult(@RequestBody QueryAlipayAuthModel queryModel) {
        log.info("getAlipayAuthResult|payModel={}", SerializationUtil.obj2String(queryModel));
        if (Strings.isNullOrEmpty(queryModel.getAlipayNickName()) && Strings.isNullOrEmpty(queryModel.getSignBizNo())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入支付宝账号");
        }

        User user = signerCheckHelper.checkSign(queryModel);
        UserShard userShard = userShardManager.getById(user.getId());

        try {
            ShardUtil.setShardContext(userShard.getShardId());
            AlipayUser alipayUser = null;
            if (!Strings.isNullOrEmpty(queryModel.getAlipayNickName())) {
                alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), queryModel.getAlipayNickName());
            } else if (!Strings.isNullOrEmpty(queryModel.getSignBizNo())) {
                alipayUser = alipayUserManager.findBySignBizNo(user.getId(), queryModel.getSignBizNo());
            }

            if (alipayUser == null || alipayUser.getIsDeleted() == 1) {
                throw new BusinessException(PoseidonErrorCode.ALIPAY_USER_NO_EXIST, "该用户尚未发起签约或已被删除");
            }

            OpenAlipayUserDto dto = OpenAlipayUserDto.getInstance();
            dto.setAlipayNickName(alipayUser.getAlipayNickName());
            dto.setSignBizNo(alipayUser.getSignBizNo());
            dto.setAlipayUid(alipayUser.getAlipayUserId());
            dto.setStatus(alipayUser.getStatus());
            dto.setExpiresIn(alipayUser.getExpiresIn());
            return new ResultData<>(dto);
        } finally {
            ShardUtil.cleanShardContext();
        }
    }

    private String doAlipayAuth(OpenAlipayAuthModel authModel, User user) throws AlipayApiException {
        String alipayNickName = authModel.getAlipayNickName();
        Long userId = user.getId();
        //先从缓存中查，如果没有再请求新的
        Object authUrl = redisHelper.get(RedisKey.AUTH_ALIPAY_USER_URL + ":" + user.getId() + ":" + alipayNickName + ":" + authModel.getReturnUrl());
        if (authUrl != null) {
            AlipayUser alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), alipayNickName);
            if (alipayUser != null) {
                alipayUser.setIsDeleted(0);
                alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
            }
            return authUrl.toString();
        }

        String isvBizId = userId + "-" + System.currentTimeMillis();
        String authPageUrl = xpayAlipayClient.alipayOpenInviteOrderCreate(isvBizId, authModel.getAlipayNickName(), authModel.getReturnUrl());

        AlipayUser alipayUser = alipayUserManager.findByAlipayNickName(userId, alipayNickName);
        if (alipayUser == null) {
            alipayUser = AlipayUser.getInstance();
            alipayUser.setUserId(userId);
            alipayUser.setMobile(user.getMobile());
            alipayUser.setAlipayNickName(alipayNickName);
            // 异步消息需要根据isvBizId来获取对应token
            alipayUser.setIsvBizId(isvBizId);
            alipayUser.setStatus(AlipayUserStatus.NO);
            alipayUser.setIsDeleted(0);
            alipayUserManager.save(alipayUser);

            //将第一个绑定的号作为主支付宝账号
            AlipayUserSearchModel searchModel = new AlipayUserSearchModel();
            searchModel.setUserId(user.getId());
            long count = alipayUserManager.searchCount(searchModel);
            if (count == 1L) {
                User selectedUser = userManager.getById(user.getId());
                selectedUser.setAlipayNickName(alipayNickName);
                selectedUser.setAlipayUserId(alipayUser.getId());
                userManager.updateByPrimaryKeyWithVersion(selectedUser);
            }
        } else {
            alipayUser.setStatus(AlipayUserStatus.NO);
            alipayUser.setIsvBizId(isvBizId);
            alipayUser.setIsDeleted(0);
            alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
        }

        redisHelper.set(RedisKey.AUTH_ALIPAY_USER_URL + ":" + user.getId() + ":" + alipayNickName + ":" + authModel.getReturnUrl(), authPageUrl, 60 * 30L);
        return authPageUrl;
    }

    private String doAlipaySign(OpenAlipaySignModel authModel, User user) throws AlipayApiException {
        String signBizNo = authModel.getSignBizNo();
        Long userId = user.getId();
        //先从缓存中查，如果没有再请求新的
        Object authUrl = redisHelper.get(RedisKey.AUTH_ALIPAY_USER_URL + ":" + user.getId() + ":" + signBizNo + ":" + authModel.getReturnUrl());
        if (authUrl != null) {
            AlipayUser alipayUser = alipayUserManager.findBySignBizNo(user.getId(), signBizNo);
            if (alipayUser != null) {
                alipayUser.setIsDeleted(0);
                alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
            }
            return authUrl.toString();
        }

        String isvBizId = userId + "-" + System.currentTimeMillis();
        String authPageUrl = xpayAlipayClient.alipayOpenInviteOrderCreate(isvBizId, null, authModel.getReturnUrl());

        AlipayUser alipayUser = alipayUserManager.findBySignBizNo(user.getId(), signBizNo);
        if (alipayUser == null) {
            alipayUser = AlipayUser.getInstance();
            alipayUser.setSignBizNo(signBizNo);
            alipayUser.setUserId(userId);
            alipayUser.setMobile(user.getMobile());
            // 异步消息需要根据isvBizId来获取对应token
            alipayUser.setIsvBizId(isvBizId);
            alipayUser.setStatus(AlipayUserStatus.NO);
            alipayUser.setIsDeleted(0);
            alipayUserManager.save(alipayUser);

            //将第一个绑定的号作为主支付宝账号
            AlipayUserSearchModel searchModel = new AlipayUserSearchModel();
            searchModel.setUserId(user.getId());
            long count = alipayUserManager.searchCount(searchModel);
            if (count == 1L) {
                User selectedUser = userManager.getById(user.getId());
                selectedUser.setAlipayUserId(alipayUser.getId());
                userManager.updateByPrimaryKeyWithVersion(selectedUser);
            }
        } else {
            alipayUser.setStatus(AlipayUserStatus.NO);
            alipayUser.setSignBizNo(signBizNo);
            alipayUser.setIsvBizId(isvBizId);
            alipayUser.setIsDeleted(0);
            alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
        }

        redisHelper.set(RedisKey.AUTH_ALIPAY_USER_URL + ":" + user.getId() + ":" + signBizNo + ":" + authModel.getReturnUrl(), authPageUrl, 60 * 30L);
        return authPageUrl;
    }

}
